import 'package:meta/meta.dart';
import 'package:list_test/weight.dart';
import 'package:list_test/store/actions.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:firebase_database/firebase_database.dart';
import 'package:redux/redux.dart';

@immutable
class ReduxState {
  final List<Weight> entries;
  final FirebaseUser firebaseUser;
  final DatabaseReference mainReference;
  final bool hasEntryBeenAdded;
  ReduxState({ this.entries, this.firebaseUser, this.mainReference, this.hasEntryBeenAdded });

  ReduxState copyWith({
    List<Weight> entries,
    FirebaseUser firebaseUser,
    DatabaseReference mainReference,
    bool hasEntryBeenAdded
  }) {
    return new ReduxState(
      mainReference: mainReference ?? this.mainReference,
      firebaseUser: firebaseUser ?? this.firebaseUser,
      entries: entries ?? this.entries,
      hasEntryBeenAdded: hasEntryBeenAdded ?? this.hasEntryBeenAdded
    );
  }
}

firebaseMiddleware(Store store, action, NextDispatcher next) {
  print(action.runtimeType);
  if (action is InitAction) {
    if (store.state.firebaseUser == null) {
      FirebaseAuth.instance.currentUser().then((user) {
        if (user != null) {
          store.dispatch(new UserLoadedAction(user));
        } else {
          FirebaseAuth.instance.signInAnonymously()
            .then((user) => store.dispatch(new UserLoadedAction(user)));
        }
      });
    }
  } else if (action is AddEntryAction) {
    store.state.mainReference.push().set(action.weightEntry.toJson());
  } else if (action is EditEntryAction) {
    store.state.mainReference.child(action.weightEntry.key).set(action.weightEntry.toJson());
  }
  next(action);
  if (action is UserLoadedAction) {
    store.dispatch(new AddDatabaseReferenceAction(
      FirebaseDatabase.instance
        .reference()
        .child(store.state.firebaseUser.uid)
        .child('entries')
      ..onChildAdded
        .listen((event) => store.dispatch(new OnAddedAction(event)))
      ..onChildChanged
        .listen((event) => store.dispatch(new OnEditedAction(event)))
    ));
  }
}

ReduxState stateReducer(ReduxState state, action) {
  if (action is InitAction) {
    FirebaseDatabase.instance.setPersistenceEnabled(true);
  } else if (action is AddDatabaseReferenceAction) {
    return state.copyWith(mainReference: action.databaseReference);
  } else if (action is OnAddedAction) {
    return _onEntryAdded(state, action.event);
  } else if (action is OnEditedAction) {
    return _onEntryEdited(state, action.event);
  } else if (action is UserLoadedAction) {
    return state.copyWith(firebaseUser: action.firebaseUser);
  } else if (action is AcceptEntryAddedAction) {
    return state.copyWith(hasEntryBeenAdded: false);
  }
  return state;
}

dynamic _onEntryAdded(ReduxState state, Event event) {
  return state.copyWith(
    entries: <Weight>[]
      ..addAll(state.entries)
      ..add(new Weight.fromSnapshot(event.snapshot))
      ..sort((w1, w2) => w2.dateTime.compareTo(w1.dateTime))
  );
}

dynamic _onEntryEdited(ReduxState state, Event event) {
  var oldValue = state.entries.singleWhere((entry) => entry.key == event.snapshot.key);
  
  return state.copyWith(
    entries: <Weight>[]
      ..addAll(state.entries)
      ..[state.entries.indexOf(oldValue)] = 
        new Weight.fromSnapshot(event.snapshot)
      ..sort((w1, w2) => w2.dateTime.compareTo(w1.dateTime))
  );
}